﻿using AngleSharp.Dom;
using EMC.VISITOR.Application;
using EMC.VISITOR.Application.Entity;
using EMC.VISITOR.Application.Enums;
using EMC.VISITOR.Core;
using EMC.VISITOR.Core.Service;
using Furion;
using Furion.DatabaseAccessor;
using Furion.JsonSerialization;
using Mapster;
using Masuit.Tools;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Forms;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter;
using Nest;
using NewLife.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using SqlSugar;
using SqlSugar.Extensions;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Yitter.IdGenerator;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinUserInfoBatchGetRequest.Types;
using static SKIT.FlurlHttpClient.Wechat.Api.Models.ComponentTCBBatchGetEnvironmentIdResponse.Types;
using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateApplyForSubjectApplymentRequest.Types;
using static SKIT.FlurlHttpClient.Wechat.TenpayV3.Models.CreateRefundDomesticRefundRequest.Types.Amount.Types;

namespace EMC.VISITOR.ApplicationExtend
{
    [ApiDescriptionSettings(MyBusConst.GroupName, Order = 100)]
    public class VisitLogExtendService : VisitLogService
    {

        private readonly ISqlSugarClient _dbTemp;
        private readonly SysCacheService _sysCacheService;
        protected readonly IHttpClient _resilienceHttpClient;


        private readonly VisitorType[] TSFKTYPES = new VisitorType[] { VisitorType.Customer, VisitorType.GovernmentPersonnel, VisitorType.CZRY, VisitorType.MSRY, VisitorType.ElsePersonnel };
        public VisitLogExtendService(SqlSugarRepository<VisitLog> rep,
            SqlSugarRepository<SysDictType> repDType,
            ISqlSugarClient db,
            SysCacheService sysCache,
            IHttpClient httpClient) : base(rep, repDType)
        {
            _dbTemp = db;
            _sysCacheService = sysCache;
            _resilienceHttpClient = httpClient;
        }
        [AllowAnonymous]
        [HttpGet]
        public async Task<JRResult<string>> QueryUserByName(string name)
        {
            var _db = _rep.Context;
            if (name.IsNullOrEmpty())
            {
                return CustomeResult.Fail<string>($"请输入被访人姓名！");
            }
            name = HttpUtility.UrlDecode(name);
            name = name.Trim().Replace(" ", "");
            var JT = ChineseConverter.Convert(name, ChineseConversionDirection.TraditionalToSimplified);//转简体
            var FT = ChineseConverter.Convert(name, ChineseConversionDirection.SimplifiedToTraditional);//转繁体

            var user = await _db.MyQueryable<SysUser>().Where(r => r.RealName.Trim() == JT || r.RealName.Trim() == FT).FirstAsync();
            if (user == null)
                return CustomeResult.Fail($"访客系统中未找到被访人：{name}");

            return CustomeResult.Success(user?.Phone);
        }

        /// <summary>
        /// 黑名单验证
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private async Task<JRResult<string>> BlackVisitCheck(ISqlSugarClient _db, AddVisitLogInput input)
        {
            if (!input.IdCard.IsNullOrEmpty() && !input.Visitor.IsNullOrEmpty() && input.Type == VisitorType.Build)
            {
                var now = DateTime.Now;
                input.IdCard = input.IdCard.Trim();
                input.Visitor = input.Visitor.Trim();
                var existDB = await _db.MyQueryable<VistLogBlack>().FirstAsync(r => r.IsEnabled == true && r.IdCard == input.IdCard &&
                  (SqlFunc.Between(now, r.StartTime, r.EndTime))
                  );
                if (existDB != null) return CustomeResult.Fail($"访客：【{input.Visitor}】已被纳入黑名单中，原因：{existDB.Remark}，请联系相关人员！");
            }
            return CustomeResult.Success();
        }
        private async Task<JRResult<string>> CheckInput(AddVisitLogInput input, params string[] excludeFileds)
        {

            if (input.Visitor.IsNullOrEmpty() && input.Type != VisitorType.GovernmentPersonnel) return CustomeResult.Fail("访客姓名为必填项！");
            if (input.Type == VisitorType.Build && !excludeFileds.Contains(nameof(input.VisitArea)) && input.VisitArea.IsNullOrEmpty()) return CustomeResult.Fail("作业区域为必填项！");
            if (input.Type == VisitorType.Driver && !excludeFileds.Contains(nameof(input.CarNo)) && input.CarNo.IsNullOrEmpty())
            {
                input.CarNo = "人员入场";
            }
            //if (input.Type == VisitorType.Driver && input.CarNo.IsNullOrEmpty())
            //    input.CarNo = "人员入场";
            if (input.Type == VisitorType.Driver && !excludeFileds.Contains(nameof(input.DocImg)) && input.DocImg.IsNullOrEmpty()) return CustomeResult.Fail("行驶证驾驶证为必上传项！");

            var types = new VisitorType?[] { VisitorType.Usual, VisitorType.Driver };
            if (types.Contains(input.Type) && !input.LeaderId.HasValue) return CustomeResult.Fail("被访单位、被访人为必填项！");

            var TSTYPES = new VisitorType?[] { VisitorType.GovernmentPersonnel, VisitorType.Customer, VisitorType.MSRY, VisitorType.ElsePersonnel }; //政府人员、客户、其它人员
            if (!TSTYPES.Contains(input.Type))
                if (input.Vimg.IsNullOrEmpty()) return CustomeResult.Fail("访客头像照片不能为空！");

            if (input.Type == VisitorType.Build)
            {
                if (input.IdCard.IsNullOrEmpty()) return CustomeResult.Fail("访客证件号不能为空！");

                if (!input.Visitor.IsNullOrEmpty())
                {
                    input.Visitor = input.Visitor.Trim();
                    input.Visitor = ChineseConverter.Convert(input.Visitor, ChineseConversionDirection.TraditionalToSimplified);//转简体
                }
            }


            if (!input.CarNo.IsNullOrEmpty())
            {
                if (input.CarNo != "人员入场")
                {
                    var maxLength = new int[] { 7, 8 };
                    if (!maxLength.Contains(input.CarNo.Length))
                    {
                        return CustomeResult.Fail("请输入正确的车牌号！");
                    }
                }
            }
            if (input.VisitTime > input.VendTime) return CustomeResult.Fail("预约开始时间不能大于结束时间！");
            if (input.VendTime < DateTime.Now) return CustomeResult.Fail("请录入正确的预约结束时间！");

            TimeSpan difference = input.VendTime.Value - input.VisitTime.Value;
            double daysBetween = difference.TotalHours;
            var maxVisitimes = await CommonUtil.GetConfigValue("visitor_max_vistime", "visitor_tsdep");
            var times = maxVisitimes["visitor_max_vistime"].Split('|')[0].Split(',');
            //最大预约时间限制
            switch (input.Type)
            {
                case VisitorType.Usual:

                    if (Math.Abs(daysBetween) > times[0].ObjToMoney())
                        return CustomeResult.Fail($"可预约时间为:{times[0]}小时内！");
                    break;
                case VisitorType.Build:
                    //if (Math.Abs(daysBetween) > times[1].ObjToMoney())
                    //    return CustomeResult.Fail($"可预约时间为:{times[1]}小时内！");
                    break;
                case VisitorType.Driver:
                    if (input.DeptId.HasValue && maxVisitimes["visitor_tsdep"].Contains(input.DeptId.ToString()))
                    {
                        if (Math.Abs(difference.TotalDays) > 30)
                            return CustomeResult.Fail($"最大预约不能超过30天！");
                        else
                        {
                            input.VendTime = input.VisitTime.Value.AddDays(30);
                            return CustomeResult.Success();
                        }
                    }
                    if (input.VisitTime.ObjToDate().Date != DateTime.Now.Date && (!input.Id.HasValue || input.Id <= 0)) //只有新增的时候需要卡控
                    {
                        return CustomeResult.Fail($"只允许当日预约！");
                    }
                    //if (Math.Abs(daysBetween) > times[2].ObjToMoney())
                    //    return CustomeResult.Fail($"可预约时间为:{times[2]}小时内！");
                    break;
                default:
                    if (Math.Abs(difference.TotalDays) > times[3].ObjToMoney())
                        return CustomeResult.Fail($"特殊访客可预约天数为:{times[3]}天内！");
                    break;
            }
            return CustomeResult.Success();
        }

        /// <summary>
        /// 超时放行或异常放行
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [AllowAnonymous]
        public async Task<JRResult<dynamic>> ErrorGoOut(UpdateVisitLogInput input)
        {
            var _db = _rep.Context;
            var vis = await _db.MyQueryable<VisitLog>().FirstAsync(r => r.Id == input.Id);
            if (vis == null)
            {
                return CustomeResult.Fail<dynamic>($"未找到访客信息，无法通过此功能放行！");
            }

            if (vis.Status < ProcessStatus.Agreed)
            {
                return CustomeResult.Fail<dynamic>($"状态为：{vis.Status.GetDescription()}，无法通过此功能放行！");
            }
            if (vis.Status >= ProcessStatus.Agreed)
            {
                vis.AuthResultMessage += $"状态：{vis.Status.GetDescription()}，异常放行！";
            }
            if (vis.Status >= ProcessStatus.GoneOut)
            {
                vis.AuthResultMessage += "超时放行！";
            }
            vis.VendTime = DateTime.Now.AddMinutes(10);
            vis.Status = ProcessStatus.WaitToEnter;
            vis.UpdateTime = DateTime.Now;
            await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new
            {
                r.Status,
                r.VendTime,
                r.UpdateTime
            }).ExecuteCommandAsync();


            return CustomeResult.Success<dynamic>("异常放行成功，10分钟内有效！");
        }

        /// <summary>
        /// 删除海康人脸设备接收任务堵塞的问题
        /// </summary>
        /// <returns></returns>
    
        /// <summary>
        /// 预约
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [AllowAnonymous]
        public async Task<JRResult<dynamic>> VisTypeEnterCount()
        {
            var _db = _rep.Context;
            var today = DateTime.Today;
            var query = _db.MyQueryable<VisitLog>()
                .LeftJoin<DoorInOutRecord>((u, doorRecord) => u.Id.ToString() == doorRecord.personId)
                .LeftJoin<HKCrossRecord>((u, doorRecord, carRecord) => u.CarNo == carRecord.plateNo)
                .LeftJoin<SysUser>((u, doorRecord, carRecord, user) => u.LeaderId == user.Id)
                .LeftJoin<WchatMessage>((u, doorRecord, carRecord, user, msg) => u.Id == msg.VisitorId)
                .LeftJoin<SysOrg>((u, doorRecord, carRecord, user, msg, org) => user.OrgId == org.Id)
                ;
            //進場訪客數據
            var visEnterList = await query.Clone().Where(u => u.Status == ProcessStatus.Entered && u.Type == VisitorType.Driver)
                        .GroupBy((u, doorRecord, carRecord, user, msg, org) => new { u.Visitor, u.Type, u.Vphone, u.Vcompany, u.VisitArea, u.DeptId, u.CarNo, user.RealName, user.Phone, org.Name })
                        .Select((u, doorRecord, carRecord, user, msg, org) => new
                        {
                            u.Visitor,
                            u.Vphone,
                            u.Vcompany,
                            u.CarNo,
                            u.Type,
                            u.VisitArea,
                            u.DeptId,
                            LaderName = user.RealName,
                            LaderPhone = user.Phone,
                            LaderOrg = org.Name,
                            wchatMessageCreateTime = SqlFunc.AggregateMax(msg.CreateTime),
                            VisitTime = SqlFunc.AggregateMax(u.VisitTime),
                            VendTime = SqlFunc.AggregateMax(u.VendTime),
                            lastDoorTime = SqlFunc.AggregateMax(doorRecord.eventTimeOk),
                            lastCarTime = SqlFunc.AggregateMax(carRecord.corssTimeOk)
                        })
                        .ToListAsync();


            //当前场内访客
            var orgs = await _db.MyQueryable<SysOrg>().Where(r => r.Pid != 0).ToListAsync();
            Func<VisitorType, dynamic> areaVisitorEchart = (type) =>
            {
                List<dynamic> dataList = new List<dynamic>();
                if (type == VisitorType.Driver)
                {
                    var driverEable = visEnterList.Where(r => r.Type == type && !r.VisitArea.IsNullOrEmpty());
                    var storageOrgs = orgs.Where(r => r.Pid == orgs.FirstOrDefault(c => c.Code == CommonConst.StorageCode).Id).OrderBy(r => r.OrderNo).ToList();
                    if (storageOrgs.Count() > 0)
                    {
                        var driverVisList = visEnterList.Where(c => c.Type == type).ToList().DeepClone();
                        storageOrgs.ForEach(r =>
                        {
                            dataList.Add(new
                            {
                                name = r.Name,
                                orgId = r.Id,
                                data = driverVisList.Where(c => c.DeptId == r.Id).Count(),
                                maxStopCount = r.MaxCarCount,
                                CarNos = driverVisList.Where(c => c.DeptId == r.Id).Select(c => new
                                {
                                    c.CarNo,
                                    c.VisitArea,
                                    c.Visitor,
                                    c.Vcompany,
                                    c.Vphone
                                }).ToList()
                            });
                            //driverVisList = driverVisList.Where(c => !c.VisitArea.Contains(r.Name)).ToList(); //排除掉这个仓库，不然会在下个循环中又统计了这个仓库的信息
                        });
                    }
                }
                var visitorList = visEnterList.Where(r => r.Type == type);
                return dataList;
            };

            var list = areaVisitorEchart(VisitorType.Driver);
            return CustomeResult.Success<dynamic>(list);
        }
        ///// <summary>
        ///// 延长预约结束时间
        ///// </summary>
        ///// <param name="input"></param>
        ///// <returns></returns>
        //[HttpPost]
        //[AllowAnonymous]
        //public async Task<JRResult<string>> AddVisEndTime(DeleteVisitLogInput input)
        //{

        //}
        [AllowAnonymous]
        [HttpPost]
        public override async Task<JRResult<string>> Add(AddVisitLogInput input)
        {
            //await _baseVistorManage.SendEmailWechat(input);
            var checkInput = await CheckInput(input);
            if (!checkInput.Success)
                return checkInput;

            //if (input.VisitTime < DateTime.Now.AddMinutes(-10))
            //    return CustomeResult.Fail("请输入正确的来访时间！");

            var _db = _rep.Context;
            var checkBlack = await BlackVisitCheck(_db, input);
            if (!checkBlack.Success)
                return checkBlack;

            if (input.Type.HasValue && (input.Type < VisitorType.Customer || input.Type == VisitorType.CZRY))
            {
                var existVisitor = await _db.MyQueryable<VisitLog>()
                    .FirstAsync(r => r.Vphone == input.Vphone.Trim() && r.Status < ProcessStatus.GoneOut);

                if (existVisitor != null)
                    return CustomeResult.Fail("系统中已存在相同的访客,请勿重复申请！");

                if (!input.IdCard.IsNullOrEmpty())
                {
                    input.IdCard = input.IdCard.Trim().Replace(" ", "");
                    existVisitor = await _db.MyQueryable<VisitLog>().FirstAsync(r => r.IdCard == input.IdCard && r.Status < ProcessStatus.GoneOut);
                    if (existVisitor != null)
                        return CustomeResult.Fail("系统中已存在相同证件号的访客,请勿重复申请！");
                }
            }
            checkInput = await CheckUserFace(input.Vimg, input.Type);
            if (!checkInput.Success)
                return checkInput;

            if (input.Position.IsNullOrEmpty())
                input.Position = "未知";
            try
            {
                input.Status = ProcessStatus.Init;
                //表示访客是被分享的访客，修改状态不需要被访人再次审核
                if (input.CreateTime.HasValue)
                {
                    input.Status = ProcessStatus.Agreed;
                    input.IsBeShared = input.Id; //被分享的访客
                }

                //选择了特殊部门不需要审核直接就可以自动通过审核
                var setting = await CommonUtil.GetConfigValue("visitor_tsdep_isopen", "visitor_tsdep", "visitor_confirm_manager_audit");
                if (setting["visitor_tsdep_isopen"].ObjToBool() && !setting["visitor_tsdep"].IsNullOrEmpty())
                {
                    var splits = setting["visitor_tsdep"].Split(',');
                    var dbOrgIds = await _db.MyQueryable<SysOrg>().Where(r => splits.Contains(r.Name)).Select(r => r.Id).ToListAsync();
                    if (input.DeptId.HasValue && dbOrgIds.Contains(input.DeptId.Value))
                    {
                        input.Status = ProcessStatus.Agreed;
                    }
                }

                if (input.Type == VisitorType.Usual && !input.Staff.IsNullOrEmpty() && input.LeaderId.HasValue && setting["visitor_confirm_manager_audit"].ObjToBool() == true) //表示需要被访人确认
                {
                    input.Staff = input.Staff.Trim().Replace(" ", "");
                    var StaffList = JFConverts(input.Staff);
                    var userStaffs = await _db.MyQueryable<SysUser>().Includes(r => r.SysOrg).Where(r => StaffList.Contains(r.RealName)).ToListAsync();
                    var userLeader = await _db.MyQueryable<SysUser>().FirstAsync(r => r.Id == input.LeaderId);
                    if (userStaffs != null && userStaffs.Count > 0 && userLeader != null && !userStaffs.Select(r => r.RealName).Contains(userLeader.RealName))
                    {
                        input.StaffConfirm = "0"; //先发送邮件给被访人的标记
                        //input.LeaderId = userStaff.Id;
                    }
                    if (userStaffs != null && userStaffs.Count > 0 && userLeader != null)
                    {
                        //系统中此用户存在多个部门，并且其有审核权限
                        var TEMP = userStaffs.FirstOrDefault(r => r.OrgId == userLeader.OrgId);
                        if (TEMP != null && TEMP.SysOrg != null && TEMP.SysOrg.Level.HasValue && TEMP.SysOrg.Level.Value == 2)
                            input.StaffConfirm = "1";
                    }
                }
                var notSendMessageVisTypes = new VisitorType?[] { VisitorType.Build, VisitorType.Customer, VisitorType.MSRY };

                if (notSendMessageVisTypes.Contains(input.Type))  //施工人员不需要审核，已在Flow系统中申请过
                {
                    input.Status = ProcessStatus.Agreed;
                }
                input.Id = YitIdHelper.NextId();

                if (!input.CarNo.IsNullOrEmpty())
                {
                    input.CarNo = input.CarNo.Replace(" ", "").Trim().ToUpper();
                    //系统中已经存在相同的车牌号了，不能再添加这个相同的车牌号了
                    var dbExistCarNoFlag = await _db.MyQueryable<VisitLog>().AnyAsync(r => r.CarNo == input.CarNo && r.Id != input.Id && r.Status < ProcessStatus.GoneOut);
                    if (dbExistCarNoFlag)
                        input.CarNo = null;
                }

                var result = await base.Add(input);

                if (!result.Success)
                    return CustomeResult.Fail(result.Message);

                VisitLogDetail detail = new VisitLogDetail
                {
                    Id = input.Id.Value,
                    personId = input.Id.Value,
                    CarLastTime = DateTime.Now
                };

                await _db.MyInsertable<VisitLogDetail>(detail).ExecuteCommandAsync();

                return CustomeResult.Success();
            }
            catch (Exception ex)
            {
                return CustomeResult.Fail(ex.Message);
            }
        }
        private string[] JFConverts(string name)
        {
            var JT = ChineseConverter.Convert(name, ChineseConversionDirection.TraditionalToSimplified);//转简体
            var FT = ChineseConverter.Convert(name, ChineseConversionDirection.SimplifiedToTraditional);//转繁体
            return new string[] { JT, FT };
        }

        /// <summary>
        /// 施工人员立即开干卡控
        /// </summary>
        /// <returns></returns>
        private async Task<JRResult<string>> HACheck(UpdateVisitLogInput input, ISqlSugarClient _db)
        {
            if (input.Type != VisitorType.Build)
                return CustomeResult.Success();

            if (input.Vreason.IsNullOrEmpty())
                return CustomeResult.Success();

            var setting = await CommonUtil.GetConfigValueToBool("sgkg");
            if (setting == false)
                return CustomeResult.Success();


            var dbVisitors = await _db.MyQueryable<VisitLog>().Where(r => r.Status < ProcessStatus.GoneOut && r.Vcompany == input.Vcompany && r.Vreason.Contains(input.Vreason)).ToListAsync();
            if (dbVisitors.Count <= 0)
                return CustomeResult.Success();

            var vreasons = input.Vreason.Split('|');
            var flows = await _db.MyQueryable<FlowSystemSG>().Where(r => r.supplier_name == input.Vcompany
             && vreasons.Contains(r.project_name)).ToListAsync();

            flows = flows.Where(r => !r.personlist.IsNullOrEmpty()).ToList();
            if (flows.Count <= 0) return CustomeResult.Success();

            //flow总人数
            var totalCount = flows.Sum(r => r.GetPersonList().Count);

            if (dbVisitors.Count > totalCount)
                return CustomeResult.Fail($"共选择【{flows.Count}】个项目，可参与人数：{totalCount}，现已超员，不可加入！");

            var jfs = JFConverts(input.Visitor);

            List<string> sp = new List<string>();
            foreach (var flow in flows)
            {
                if (!JFConverts(flow.personlist)[0].Contains(jfs[0]))
                    sp.Add($"访客不在此项目：{flow.project_name}");
            }
            if (sp.Count > 0)
                return CustomeResult.Fail($"访客不在此项目：{string.Join(",", sp)}");

            return CustomeResult.Success();
        }
        [AllowAnonymous]
        [HttpPost]
        public override async Task<JRResult<string>> Update(UpdateVisitLogInput input)
        {
            var _db = _rep.Context;
            var checkBlack = await BlackVisitCheck(_db, input.Adapt<AddVisitLogInput>());
            if (!checkBlack.Success)
                return checkBlack;

            var existVisitor = await _db.MyQueryable<VisitLog>()
            .WhereIF(input.Type == VisitorType.Build, r => r.Id == input.Id && r.Status < ProcessStatus.GoneOut)
            .WhereIF((input.Type != VisitorType.Build && input.Type < VisitorType.Customer) || input.Type == VisitorType.CZRY, r => r.Vphone == input.Vphone.Trim() && r.Status < ProcessStatus.GoneOut)
            .WhereIF(input.Type >= VisitorType.Customer && input.Type != VisitorType.CZRY, r => r.Id == input.Id && r.Status < ProcessStatus.GoneOut)
            .FirstAsync();
            if (existVisitor == null)
                return CustomeResult.Fail("此访客已离开公司或完成流程，请重新申请！");

            if (input.Position.IsNullOrEmpty())
                input.Position = "未知";
            //表示只更新位置信息
            if (input.IsBeShared == -1)
            {
                var TEMP = input.Adapt<VisitLog>();
                await _db.MyUpdateable<VisitLog>(TEMP).UpdateColumns(r => new { r.Position }).ExecuteCommandAsync();
                return CustomeResult.Success("訪客位置信息已更新！");
            }

            var checkInput = await CheckInput(input.Adapt<AddVisitLogInput>(), nameof(input.CarNo));
            if (!checkInput.Success)
                return checkInput;
            if ((input.Status == ProcessStatus.Agreed || input.Status == ProcessStatus.Rejected) && existVisitor.Status > ProcessStatus.Rejected)
                return CustomeResult.Fail("當前訪客的狀態已更新，請刷新頁面！");

            //表示访客删除自己的来访 (不想来了)
            if (input.Status == ProcessStatus.GoneOut)
            {
                existVisitor.VendTime = DateTime.Now;
                existVisitor.UpdateTime = DateTime.Now;
                existVisitor.AuthResultMessage = "用户手动结束访问！";
                await _db.MyUpdateable<VisitLog>(existVisitor).UpdateColumns(r => new { r.VendTime, r.UpdateTime }).ExecuteCommandAsync();
                await _rep.Context.MyInsertable<VisitLog_History>(existVisitor.Adapt<VisitLog_History>()).ExecuteCommandAsync();
                return CustomeResult.Success("删除来访中，请稍等片刻！");
            }

            checkInput = await CheckUserFace(input.Vimg, input.Type);
            if (!checkInput.Success)
                return checkInput;

            //施工人员与Flow单比对卡控
            checkInput = await HACheck(input, _db);
            if (!checkInput.Success)
                return checkInput;

            if (!input.CarNo.IsNullOrEmpty())
            {
                input.CarNo = input.CarNo.Replace(" ", "").Trim().ToUpper();
                //系统中已经存在相同的车牌号了，不能再添加这个相同的车牌号了
                var dbExistCarNoFlag = await _db.MyQueryable<VisitLog>().AnyAsync(r => r.CarNo == input.CarNo && r.Id != input.Id && r.Status < ProcessStatus.GoneOut);
                if (dbExistCarNoFlag)
                    input.CarNo = null;
            }
            if (!input.GoodsInfo.IsNullOrEmpty())
            {
                input.GoodsInfo = GetGoodsInfo(input.GoodsInfo);
            }

            var result = await base.Update(input);
            if (!result.Success)
                return result;



            return await UpdateBatch(new UpdateBatchInput { Status = input.Status, Ids = new long[] { input.Id.Value } });
        }

        private async Task<JRResult<string>> CheckUserFace(string faceUrl, VisitorType? vType)
        {
            if (faceUrl.IsNullOrEmpty())
                return CustomeResult.Success();

            var _db = _rep.Context;
            var settings = await CommonUtil.GetConfigValue("visitor_hk_checkface", "visitor_hk_checkface_type_nocheck");
            var checkFaceFlag = settings["visitor_hk_checkface"].ObjToBool();
            if (!checkFaceFlag) //不检测人脸
                return CustomeResult.Success();

            if (vType.HasValue)
            {
                var noChecks = settings["visitor_hk_checkface_type_nocheck"];
                if (noChecks.Split(',').Select(r => (VisitorType)Enum.Parse(typeof(VisitorType), r)).ToList().Contains(vType.Value))
                    return CustomeResult.Success();
            }

            var faceName = Path.GetFileName(faceUrl);
            var model = await _db.MyQueryable<HKFaceCheck>().FirstAsync(r => r.faceUrl.Contains(faceName));
            if (model == null)
                return CustomeResult.Fail("未找到人脸信息！");

            if (!model.checkResult.HasValue)
                return CustomeResult.Fail("人脸检测中...请稍后点击提交!");

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("face detect error, please check face pic"))
                model.statusMessage = "人脸照片错误，请更换正确人脸照片";

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("face score too low"))
                model.statusMessage = "人脸评分太低，请更换清晰人脸照片";

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("eye distance too small"))
                model.statusMessage = "眼睛距离太窄，请更换人脸照片";

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("color confidence too low"))
                model.statusMessage = "人脸颜色较暗，请更换人脸照片";

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("visible too low"))
                model.statusMessage = "人脸可见度太低，请更换人脸照片";

            if (!model.statusMessage.IsNullOrEmpty() && model.statusMessage.Contains("gray too large or too small"))
                model.statusMessage = "人脸照片灰度值异常，请更换人脸照片";
            if (!model.checkResult.Value)
                return CustomeResult.Fail(model.statusMessage);

            return CustomeResult.Success();
        }

        //[HttpPost]
        //public async Task<JRResult<string>> ShareAdd(AddVisitLogInput input)
        //{

        //}
        [AllowAnonymous]
        [HttpPost]
        public async Task<JRResult<string>> UpdateBatch(UpdateBatchInput input)
        {
            if (input.Ids == null)
                return CustomeResult.Fail("请传入正确的用户Ids");
            var _db = _rep.Context;
            var dbVisitors = await _db.MyQueryable<VisitLog>().Where(r => input.Ids.Contains(r.Id)).ToListAsync();
            if (dbVisitors.Count <= 0)
                return CustomeResult.Fail("根据传入的用户Ids未找到用户信息！");


            string message = string.Empty;

            List<VisitLog> visitors = new List<VisitLog>();
            for (int i = 0; i < input.Ids.Length; i++)
            {
                var vis = dbVisitors.FirstOrDefault(r => r.Id == input.Ids[i]);
                if (vis == null) continue;

                if ((input.Status == ProcessStatus.Agreed || input.Status == ProcessStatus.Rejected) && vis.Status > ProcessStatus.Rejected)
                    message += $"訪客：{vis.Visitor},的狀態已更新，請刷新頁面！";

                //预约开始时间不等于今天则不让预约
                if ((input.Status == ProcessStatus.HwAgreed || input.Status == ProcessStatus.WaitToEnter) && vis.VisitTime.Value.Date > DateTime.Today)
                {
                    message += $"訪客：{vis.Visitor},的预约时间为：{vis.VisitTime.Value.ToString("yyyy-MM-dd")},请勿提前扫码！";
                }
                vis.Status = input.Status;
                vis.UpdateTime = DateTime.Now;
                if (input.DeptIds != null && input.DeptIds.Length == input.Ids.Length)
                {
                    vis.DeptId = input.DeptIds[i];
                }
                visitors.Add(vis);
            }

            if (!message.IsNullOrEmpty())
                return CustomeResult.Fail(message);

            //是否启用一般访客需要被访人确认然后经理审批流程
            var setting = await CommonUtil.GetConfigValue("visitor_confirm_manager_audit");


            //门禁扫描后是否实时下发海康 True:实时下发，False:自动下发海康
            await visitors.ForEachAsync(async vis =>
                    {
                        if (vis.Type == VisitorType.Usual &&
                        vis.Status == ProcessStatus.Agreed &&
                        !vis.StaffConfirm.IsNullOrEmpty() && vis.StaffConfirm == "0"
                        && setting.ObjToBool() == true) //一般访客   被访人点击了确认动作
                        {
                            //找到未发送给主管的邮件、企业微信
                            var wchatMessages = await _db.MyQueryable<WchatMessage>().Where(r => r.IsSend == false && r.VisitorId == vis.Id && r.IsConfirm == false).ToListAsync();
                            if (wchatMessages.Count > 0)
                            {
                                //状态改为 可以发送的状态
                                wchatMessages.ForEach(r =>
                                {
                                    r.IsConfirm = true;
                                }
                                );
                                await _db.MyUpdateable<WchatMessage>(wchatMessages).UpdateColumns(r => new { r.IsConfirm }).ExecuteCommandAsync();
                                vis.Status = ProcessStatus.Check; //交给主管审核，被访人确认一下
                                vis.StaffConfirm = "1"; //被仿人已确认
                                vis.AuthResultMessage = "被仿人已确认！";
                            }
                        }

                        await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new
                        {
                            r.StaffConfirm,
                            r.Status,
                            r.UpdateTime,
                            r.AuthResultMessage,
                            r.DeptId
                        }).ExecuteCommandAsync();


                        // 10 代表被访人审核通过,将用户信息和人脸信息发送到海康
                        if (vis.Status == ProcessStatus.Agreed)
                        {
                            if (vis.Type == VisitorType.Driver)
                            {
                                var areas = vis.VisitArea.Split(',');
                                var orgs = await _db.MyQueryable<SysOrg>()
                                    .Where(pos => areas.Contains(pos.Name))
                                    .ToListAsync();
                                if (orgs.Count > 0)
                                {
                                    var hours = orgs.Sum(r => (double)r.MaxCarStopTime);
                                    vis.VisitTime = DateTime.Now;
                                    if (hours > 0)
                                        vis.VendTime = vis.VisitTime.Value.AddHours(hours);
                                }
                            }
                            vis.AuthResultMessage = "最终审核人已通过！";
                            if (!input.Audit.IsNullOrEmpty())
                                vis.LastLeaderName = input.Audit;

                            if (!vis.LastLeaderName.IsNullOrEmpty())
                                await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.VisitTime, r.VendTime, r.LastLeaderName, r.AuthResultMessage }).ExecuteCommandAsync();
                            else
                                await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.VisitTime, r.VendTime, r.AuthResultMessage }).ExecuteCommandAsync();

                        }
                        // 20 代表被访人审核拒绝
                        else if (vis.Status == ProcessStatus.Rejected)
                        {
                            vis.AuthResultMessage = "审核被拒绝！";
                            if (!input.Audit.IsNullOrEmpty())
                                vis.LastLeaderName = input.Audit;

                            if (!vis.LastLeaderName.IsNullOrEmpty())
                                await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.AuthResultMessage, r.LastLeaderName }).ExecuteCommandAsync();
                            else
                                await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.AuthResultMessage }).ExecuteCommandAsync();

                        }
                        // 25 环按同意
                        else if (vis.Status == ProcessStatus.HwAgreed)
                        {
                            vis.AuthResultMessage = "环安已同意！";
                            await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.AuthResultMessage }).ExecuteCommandAsync();
                        }
                        // 30 门卫同意，将用户权限下发到海康设备中
                        else if (vis.Status == ProcessStatus.WaitToEnter)
                        {

                            vis.AuthResultMessage = "门卫已同意！";
                            vis.Status = ProcessStatus.WaitToEnter;
                            vis.WaitToEnterTime = DateTime.Now;
                            //查看异常抬杆数据表与当前时间做比对如果

                            await _db.MyUpdateable<VisitLog>(vis).UpdateColumns(r => new { r.AuthResultMessage, r.Status, r.WaitToEnterTime }).ExecuteCommandAsync();
                        }

                        await _rep.Context.MyInsertable<VisitLog_History>(vis.Adapt<VisitLog_History>()).ExecuteCommandAsync();
                    });
            return CustomeResult.Success();
        }


        /// <summary>
        /// 施工人员的二维码每天都需要切换到环安未审核的状态
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<int> SetSGStatus()
        {
            var time = DateTime.Now;
            var _db = _rep.Context;

            #region 更改施工人员状态
            var vLogs = await _db.MyQueryable<VisitLog>()
                       .Includes(r => r.Detail).Where(r => r.Type == VisitorType.Build && (r.Status >= ProcessStatus.HwAgreed && r.Status < ProcessStatus.GoneOut)).ToListAsync();
            if (vLogs.Count > 0)
            {
                List<VisitLogDetail> details = new List<VisitLogDetail>();
                foreach (var visitor in vLogs)
                {
                    visitor.Status = ProcessStatus.Agreed;
                }
                await _db.MyUpdateable<VisitLog>(vLogs).UpdateColumns(r => new { r.Status }).ExecuteCommandAsync();
            }

            #endregion

            MessageType?[] msgTypes = new MessageType?[] { MessageType.Email, MessageType.Wchat };
            var wmessageList = await _db.MyQueryable<WchatMessage>()
                .Where(r => r.IsSend == false)
                .Includes(r => r.Visitor).ToListAsync();

            foreach (var message in wmessageList)
            {
                if (message.Visitor != null && message.Visitor.Status >= ProcessStatus.GoneOut)
                {
                    message.IsSend = true;
                    message.WchatResultMessage = "访客已完结，无需发送！";
                    await _db.MyUpdateable<WchatMessage>(message).UpdateColumns(r => new
                    {
                        r.IsSend,
                        r.WchatResultMessage
                    }).ExecuteCommandAsync();
                    continue;
                }
            }
            return vLogs.Count;
        }
        [HttpGet]
        [AllowAnonymous]
        public async Task<dynamic> LoadDoorSettings()
        {
            var _db = _rep.Context;
            var dicTypes = await _db.LoadDictTypesByCode("YBFK", "KH", "ZFRY", "HY", "SGRY");
            Func<string, VisitorType> func = (code) =>
            {
                switch (code)
                {
                    case "YBFK":
                        return VisitorType.Usual;
                        break;
                    case "KH":
                        return VisitorType.Customer;
                        break;
                    case "ZFRY":
                        return VisitorType.GovernmentPersonnel;
                        break;
                    case "HY":
                        return VisitorType.Driver;
                        break;
                    case "SGRY":
                        return VisitorType.Build;
                        break;
                }
                return VisitorType.Usual;
            };
            return dicTypes.Select(r => new
            {
                name = r.Name,
                code = r.Code,
                type = func(r.Code),
                children = r.SysDictDatas.Select(c => new
                {
                    code = c.Code,
                    name = c.Value
                })
            }).ToList();
        }

        [HttpGet]
        [AllowAnonymous]
        public async Task<dynamic> BuildAreaList()
        {
            var _db = _rep.Context;
            var dicTypes = await _db.LoadDictTypesByCode("build_area");
            return dicTypes.SysDictDatas.Select(c => new
            {
                value = c.Code,
                label = c.Value
            }).ToList();
        }



        /// <summary>
        /// 发送企业微信邀请和删除企业微信用户
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<int> SendWchatInvite()
        {
            var _db = _rep.Context;
            var wmessageList = await _db.MyQueryable<SysUserWchat>()
                .Where(r => r.IsSend == false)
                .Includes(r => r.User)
                .ToListAsync();
            if (wmessageList.Count > 0)
            {
                foreach (var message in wmessageList)
                {
                    if (message.User == null)
                    {
                        message.WchatResultMessage = "當前消息的用戶為空";
                        message.WchatSendResult = false;
                    }
                    else if (!message.User.JobNum.Contains("_"))
                    {
                        var apiRes = await OperationWchatUser(message.User, _db);
                        message.WchatResultMessage = apiRes.errmsg.Length > 200 ? apiRes.errmsg.Substring(0, 200) : apiRes.errmsg;
                        message.WchatSendResult = apiRes.success;
                    }
                    message.IsSend = true;
                }
                await _db.MyUpdateable<SysUserWchat>(wmessageList).ExecuteCommandAsync();
            }
            return wmessageList.Count();
        }
        /// <summary>
        /// 邮件服务器发生错误，调整邮件发送随机数
        /// </summary>
        /// <returns></returns>
        public async Task<int> EmailServiceErrorTZ()
        {
            var _db = _rep.Context;
            var wmessageList = await _db.MyQueryable<WchatMessage>()
            .Where(r => r.IsSend == false && r.MessageType == MessageType.Email && r.IsConfirm == true).ToListAsync();
            if (wmessageList.Count <= 0)
                return 0;

            var time = DateTime.Now;
            List<WchatMessage> needChanges = new List<WchatMessage>();
            foreach (var message in wmessageList)
            {
                var minutes = Math.Round((time - message.CreateTime.Value).TotalMinutes, 0);
                if (minutes > 10) //表示有二十分钟邮件为发送出去，服务挂壁了
                {
                    needChanges.Add(message);
                }
            }

            if (needChanges.Count <= 0)
                return 0;

            int?[] randmNumber = new int?[] { 0, 1, 2 };
            var countNumbers = needChanges.Distinct(r => r.RandomCount).Select(r => r.RandomCount).ToArray();
            randmNumber = randmNumber.Where(r => !countNumbers.Contains(r)).ToArray();
            if (randmNumber == null || randmNumber.Length <= 0)
                return 0;
            foreach (var item in needChanges)
            {
                item.RandomCount = randmNumber[new Random().Next(0, randmNumber.Length)];
            }
            await _db.MyUpdateable<WchatMessage>(needChanges).UpdateColumns(r => new
            {
                r.RandomCount
            }).ExecuteCommandAsync();

            return needChanges.Count;
        }



      
        /// <summary>
        /// 自動任務-清除所有到期的访客
        /// </summary>
        /// <param name="visitorIds"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<string> ClearAllVendTImeVistors(List<long> visitorIds = null)
        {
            string message = string.Empty;
            var _db = _rep.Context;
            try
            {
                //var maxVisitimes = await CommonUtil.GetConfigValue("visitor_max_vistime");
                //var times = maxVisitimes.Split('|')[1].ObjToInt();
                var visitors = await _db.MyQueryable<VisitLog>()
                    .WhereIF(visitorIds != null && visitorIds.Count > 0, r => visitorIds.Contains(r.Id))
                    .Where(r => r.VendTime <= DateTime.Now && r.Status < ProcessStatus.GoneOut)
                    .ToListAsync();
                if (visitors.Count > 0)
                {
                    await visitors.ForEachAsync(async vis =>
                    {
                        vis.Status = ProcessStatus.GoneOut;
                    });
                    await _db.MyUpdateable<VisitLog>(visitors).UpdateColumns(r => new { r.Status }).ExecuteCommandAsync();
                }
                message = visitors.Count().ToString();
            }
            catch (Exception ex)
            {
                message = ex.ToString();
            }
            return message;
        }

   

       
        private List<string> GetCarAuths(List<SysDictType> dicTypes, VisitorType type)
        {
            string typeString = string.Empty;
            switch (type)
            {
                case VisitorType.Usual:
                    typeString = "YBFK";
                    break;
                case VisitorType.Driver:
                    typeString = "HY";
                    break;
                case VisitorType.Build:
                    typeString = "SGRY";
                    break;
                default:
                    typeString = "YBFK";
                    break;

            }
            List<string> hasCarAuthNames = new List<string>(); //车的权限
            var dicType = dicTypes.LoadDictDataByCode(typeString);
            dicType.SysDictDatas.ForEach(r =>
            {
                if (!r.Remark.IsNullOrEmpty() && r.Code.Contains("CAR"))
                    hasCarAuthNames.AddRange(r.Remark.Split(","));
            });
            return hasCarAuthNames;
        }
        private async Task<List<HKCarPark>> GetUserHKCars(ISqlSugarClient _db, List<string> hasCarAuthNames)
        {
            var hkCarDoors = await _db.MyQueryable<HKCarPark>().ToListAsync(); //海康汽车所有门禁
            var carAuths = hkCarDoors.Where(r => hasCarAuthNames.Contains(r.parkName)).ToList();
            return carAuths;
        }
        private async Task<HKCarPark> GetUserHKCars(ISqlSugarClient _db, string parkIndex)
        {
            var hkCarDoor = await _db.MyQueryable<HKCarPark>().Where(r => r.parkIndexCode == parkIndex).FirstAsync(); //海康汽车所有门禁
            return hkCarDoor;
        }

        
        /// <summary>
        /// 判断两个字符串的差异数量
        /// </summary>
        /// <param name="str1"></param>
        /// <param name="str2"></param>
        /// <returns></returns>
        int GetDifferenceCount(string str1, string str2)
        {
            if (str1.Length != str2.Length)
            {
                return 100;
            }

            int diffCount = 0;
            for (int i = 0; i < str1.Length; i++)
            {
                if (str1[i] != str2[i])
                {
                    diffCount++;
                }
            }
            return diffCount;
        }

      
       
        /// <summary>
        /// 同步Flow客户政府人员數據
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<int> SyncFlowRecord()
        {
            var _db = _rep.Context;
            var maxReqDateTime = await _db.MyQueryable<FlowSystem>().MaxAsync(r => r.reqDate);
            if (maxReqDateTime == null)
                maxReqDateTime = new DateTime(2025, 1, 1);

            string sql = $"select * from dbo.emc_visitor_from_flow where CONVERT(DATE, req_date, 101)>='{maxReqDateTime.Value.ToString("yyyy-MM-dd")}' and cust_source in ('客戶','客户','政府') ";

            var config = App.GetOptions<DbConnectionOptions>().ConnectionConfigs.FirstOrDefault(r => r.DbName.Contains("EFNETDB"));
            using SqlSugarScopeProvider dbProvider = _dbTemp.CopyNew().GetConnectionScope(config.ConfigId);
            var flowSystems = await dbProvider.SqlQueryable<FlowSystem>(sql).ToListAsync(); //Flow系統數據

            if (flowSystems.Count <= 0)
                return 0;

            var visitorFlows = await _db.MyQueryable<FlowSystem>().Where(r => r.reqDate >= maxReqDateTime).ToListAsync();

            List<FlowSystem> insertList = new List<FlowSystem>();
            List<FlowSystem> updateList = new List<FlowSystem>();

            List<VisitLog> insertVisitorList = new List<VisitLog>();
            List<VisitLog> updateVisitorList = new List<VisitLog>();
            string format = "yyyyMMdd";
            flowSystems.ForEach(r =>
            {

                if (!r.req_date.IsNullOrEmpty())
                    r.reqDate = DateTime.ParseExact(r.req_date, format, CultureInfo.InvariantCulture);

                var visitorFlow = visitorFlows.FirstOrDefault(c => c.req_date == r.req_date && c.line_no == r.line_no);
                if (visitorFlow == null)
                {
                    r.Id = YitIdHelper.NextId();
                    insertList.Add(r);

                    var vlog = ConventToVLog(r);
                    vlog.Id = r.Id;
                    vlog.AuthResultMessage = "FLOW系统数据";
                    insertVisitorList.Add(vlog);
                }
                else
                {
                    r.Id = visitorFlow.Id;
                    updateList.Add(r);

                    var vlog = ConventToVLog(r);
                    vlog.Id = r.Id;
                    vlog.AuthResultMessage = "FLOW系统数据";
                    updateVisitorList.Add(vlog);
                }
            });


            if (insertList.Count > 0)
                await _db.MyInsertable<FlowSystem>(insertList).ExecuteCommandAsync(); //插入訪客系統
            if (updateList.Count > 0)
                await _db.MyUpdateable<FlowSystem>(updateList).ExecuteCommandAsync(); //修改訪客系統

            if (insertVisitorList.Count > 0)
                await _db.MyInsertable<VisitLog>(insertVisitorList).ExecuteCommandAsync();
            if (updateVisitorList.Count > 0)
                await _db.MyUpdateable<VisitLog>(updateVisitorList).ExecuteCommandAsync();
            return flowSystems.Count();
        }

        /// <summary>
        /// 同步Flow施工人员数据
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public async Task<int> SyncFlowSGRecord()
        {
            var _db = _rep.Context;
            var today = DateTime.Today;
            //var maxReqDateTime = await _db.MyQueryable<FlowSystemSG>().MaxAsync(r => r.ReqDateTime);
            //if (maxReqDateTime == null)
            var maxReqDateTime = new DateTime(today.Year, 1, 1);

            string sql = @$"
Select * from (
SELECT
    req_date,
	req_dept,
	req_dept_name,
	req_empl,
	req_empl_name,
	req_tel,
	project_name,
	begin_date,
	end_date,
	supplier_name,
	content_desc,
    count(1) as vcou,
	STUFF(
		(
		SELECT
			', ' + person 
		FROM
			dbo.emc_sgsq_from_flow AS e_inner 
		WHERE
			e_inner.project_name = e_outer.project_name 
			AND e_inner.req_date = e_outer.req_date 
			AND e_inner.begin_date = e_outer.begin_date 
			AND e_inner.end_date = e_outer.end_date FOR XML PATH ( '' ) 
		),
		1,
		2,
		'' 
	) AS personlist 
FROM
	dbo.emc_sgsq_from_flow as e_outer
WHERE
	begin_date >'{maxReqDateTime.ToString("yyyyMMddHHmmss")}' 
	AND supplier_name IS NOT NULL 
GROUP BY
    req_date,
	req_dept,
	req_dept_name,
	req_empl,
	req_empl_name,
	req_tel,
	project_name,
	begin_date,
	end_date,
	supplier_name,
	content_desc) A
;
";

            #region MyRegion
            //                           string sql = @$"
            //            SELECT
            //                req_dept,
            //                req_dept_name,
            //                req_empl,
            //                req_date,
            //                req_empl_name,
            //                req_tel,
            //                project_name,
            //                begin_date,
            //                end_date,
            //                supplier_name,
            //                content_desc,
            //                build_dept,
            //                build_dept_name,
            //                build_empl_name
            //FROM

            //    dbo.emc_sgsq_from_flow
            //WHERE

            //    req_date >= '{maxReqDateTime.Value.ToString("yyyy-MM-dd")}'

            //    AND supplier_name IS NOT NULL
            //GROUP BY
            //    req_dept,
            //    req_dept_name,
            //    req_empl,
            //    req_date,
            //    req_empl_name,
            //    req_tel,
            //    project_name,
            //    begin_date,
            //    end_date,
            //    supplier_name,
            //    supplier_empl,
            //    supplier_tel,
            //    person,
            //    content_desc,
            //    build_dept,
            //    build_dept_name,
            //    build_empl_name,
            //    build_tel;
            //            ";
            #endregion

            var config = App.GetOptions<DbConnectionOptions>().ConnectionConfigs.FirstOrDefault(r => r.DbName.Contains("EFNETDB"));
            using SqlSugarScopeProvider dbProvider = _dbTemp.CopyNew().GetConnectionScope(config.ConfigId);
            var flowSystems = await dbProvider.SqlQueryable<FlowSystemSG>(sql).ToListAsync(); //Flow系統數據
            //flowSystems = flowSystems.Where(r => r.supplier_name.Contains("無錫邦鑫偉業")).ToList();
            if (flowSystems.Count <= 0)
                return 0;

            string format = "yyyyMMddHHmmss";
            //施工监控日志所需要的数据
            var flowJKs = flowSystems.Adapt<List<FlowSystemSGJK>>();
            foreach (var item in flowJKs)
            {
                item.ReqDateTime = DateTime.ParseExact(item.req_date, format, CultureInfo.InvariantCulture);
                item.BeginDateTime = DateTime.ParseExact(item.begin_date, format, CultureInfo.InvariantCulture);
                item.EndDateTime = DateTime.ParseExact(item.end_date, format, CultureInfo.InvariantCulture);
                if (!item.supplier_name.IsNullOrEmpty())
                    item.supplier_name = ChineseConverter.Convert(item.supplier_name, ChineseConversionDirection.TraditionalToSimplified);//转简体
                if (!item.project_name.IsNullOrEmpty())
                    item.project_name = ChineseConverter.Convert(item.project_name, ChineseConversionDirection.TraditionalToSimplified);//转简体
            }
            var dbSGJKs = await _db.MyQueryable<FlowSystemSGJK>().Where(r => r.BeginDateTime > maxReqDateTime).ToListAsync();

            List<FlowSystemSGJK> insertSGJKs = new List<FlowSystemSGJK>();
            foreach (var flow in flowJKs)
            {
                var existDBFlag = dbSGJKs.Any(r => r.supplier_name == flow.supplier_name
                && r.project_name == flow.project_name
                && r.ReqDateTime == flow.ReqDateTime
                && r.BeginDateTime == flow.BeginDateTime
                && r.EndDateTime == flow.EndDateTime
                );
                if (!existDBFlag)
                    insertSGJKs.Add(flow);
            }

            if (insertSGJKs.Count > 0)
                await _db.MyInsertable<FlowSystemSGJK>(insertSGJKs).ExecuteCommandAsync();
            //await _db.MyDeleteable<FlowSystemSGJK>().Where(r => waitDeleteIds.Contains(r.Id)).ExecuteCommandAsync();



            flowSystems.ForEach(r =>
            {
                if (!r.begin_date.IsNullOrEmpty())
                    r.BeginDateTime = DateTime.ParseExact(r.begin_date, format, CultureInfo.InvariantCulture);
                if (!r.end_date.IsNullOrEmpty())
                    r.EndDateTime = DateTime.ParseExact(r.end_date, format, CultureInfo.InvariantCulture);

                if (!r.supplier_name.IsNullOrEmpty())
                    r.supplier_name = ChineseConverter.Convert(r.supplier_name, ChineseConversionDirection.TraditionalToSimplified);//转简体
                if (!r.project_name.IsNullOrEmpty())
                    r.project_name = ChineseConverter.Convert(r.project_name, ChineseConversionDirection.TraditionalToSimplified);//转简体
            });
            //过期的数据不要

            var groupFlowSystems = flowSystems.Where(r => r.EndDateTime > DateTime.Now).GroupBy(r => new { r.supplier_name, r.project_name }).ToList();

            var visitorFlowDBs = await _db.MyQueryable<FlowSystemSG>().Where(r => r.BeginDateTime >= maxReqDateTime).ToListAsync();



            //var visitLogDBs = await _db.MyQueryable<VisitLog>().Where(r => r.Status < ProcessStatus.GoneOut && r.Type == VisitorType.Build).ToListAsync();
            List<FlowSystemSG> insertList = new List<FlowSystemSG>();
            List<FlowSystemSG> updateList = new List<FlowSystemSG>();

            List<VisitLog> insertVisitorList = new List<VisitLog>();
            List<VisitLog> updateVisitorList = new List<VisitLog>();

            List<VisitLogDetail> insertVisitorDetailList = new List<VisitLogDetail>();

            groupFlowSystems.ForEach(group =>
            {
                //if (group.Key.project_name.Contains("金茂二厂备品间开门洞及安装护栏"))
                //{

                //}
                var r = group.FirstOrDefault(c => c.end_date == group.Max(z => z.end_date));
                if (r == null)
                    r = group.FirstOrDefault();
                group.ForEach(c =>
                {
                    c.BeginDateTime = DateTime.ParseExact(c.begin_date, format, CultureInfo.InvariantCulture);
                    c.EndDateTime = DateTime.ParseExact(c.end_date, format, CultureInfo.InvariantCulture);
                });

                //var r = group.FirstOrDefault();


                r.vcou = group.Sum(c => c.vcou);
                if (!r.req_date.IsNullOrEmpty())
                    r.ReqDateTime = DateTime.ParseExact(r.req_date, format, CultureInfo.InvariantCulture);

                if (!r.begin_date.IsNullOrEmpty())
                    r.BeginDateTime = group.Min(c => c.BeginDateTime);

                if (!r.end_date.IsNullOrEmpty())
                    r.EndDateTime = group.Max(c => c.EndDateTime);

                var personLists = group.Where(c => !c.personlist.IsNullOrEmpty()).Select(c => c.personlist).ToList();
                if (personLists.Count > 0)
                    r.personlist = string.Join(",", personLists);

                var visitorFlow = visitorFlowDBs.FirstOrDefault(c =>
                c.supplier_name == r.supplier_name && c.project_name == r.project_name);
                if (visitorFlow == null)
                {
                    r.Id = YitIdHelper.NextId();
                    insertList.Add(r);
                }
                else
                {
                    r.Id = visitorFlow.Id;
                    updateList.Add(r);
                }

                //var visitLogDB = visitLogDBs.FirstOrDefault(c => c.VisitTime == r.BeginDateTime && c.VendTime == r.EndDateTime && c.Vcompany == r.supplier_name && c.Iphone == r.req_tel);
                //if (visitLogDB == null)
                //{
                //    var vlog = SGConventToVLog(r, group.Sum(c => c.cou));
                //    if (vlog.VendTime > DateTime.Now)
                //    {
                //        vlog.Id = r.Id;
                //        vlog.AuthResultMessage = "FLOW系统数据";
                //        insertVisitorList.Add(vlog);

                //        VisitLogDetail detail = new VisitLogDetail
                //        {
                //            Id = vlog.Id,
                //            personId = vlog.Id,
                //            CarLastTime = DateTime.Now
                //        };
                //        insertVisitorDetailList.Add(detail);
                //    }
                //}
            });


            if (insertList.Count > 0)
                await _db.MyInsertable<FlowSystemSG>(insertList).ExecuteCommandAsync(); //插入訪客系統
            if (updateList.Count > 0)
                await _db.MyUpdateable<FlowSystemSG>(updateList).IgnoreColumns(nameof(FlowSystemSG.bcpersonlist)).ExecuteCommandAsync(); //修改訪客系統

            //if (insertVisitorList.Count > 0)
            //    await _db.MyInsertable<VisitLog>(insertVisitorList).ExecuteCommandAsync();
            //if (updateVisitorList.Count > 0)
            //    await _db.MyUpdateable<VisitLog>(updateVisitorList).ExecuteCommandAsync();

            //if (insertVisitorDetailList.Count > 0)
            //    await _db.MyInsertable<VisitLogDetail>(insertVisitorDetailList).ExecuteCommandAsync();

            return groupFlowSystems.Count();
        }
        private VisitLog SGConventToVLog(FlowSystemSG flow, int count)
        {
            VisitLog vlog = new VisitLog();
            vlog.Type = VisitorType.Build;
            vlog.VisitTime = flow.BeginDateTime;
            vlog.VendTime = flow.EndDateTime;
            vlog.Status = ProcessStatus.Init;
            vlog.Vcompany = flow.supplier_name;
            vlog.Vreason = flow.content_desc;
            vlog.Staff = flow.req_empl_name;
            vlog.Iphone = flow.req_tel;
            vlog.Vnum = count;
            //TODO 自动将访问部门和审核人带出
            //vlog.LeaderId = 111;
            //vlog.DeptId = 1111;
            return vlog;
        }
        private VisitLog ConventToVLog(FlowSystem flow)
        {
            string format = "yyyyMMddHHmm";

            VisitLog vlog = new VisitLog();
            if (!flow.cust_source.IsNullOrEmpty() && flow.cust_source.Contains("客戶") || flow.cust_source.Contains("客户"))
                vlog.Type = VisitorType.Customer;
            else
                vlog.Type = VisitorType.GovernmentPersonnel;
            vlog.Vphone = "00000000000";
            vlog.Visitor = $"{flow.guest_name}（{flow.jobs_title}）";
            vlog.Sex = !flow.tguest_sex.IsNullOrEmpty() && flow.tguest_sex == "男" ? SexType.Man : SexType.WoMan;
            vlog.IdCard = "000000000000000000";
            vlog.VisitTime = DateTime.ParseExact(flow.start_date, format, CultureInfo.InvariantCulture);
            vlog.VendTime = DateTime.ParseExact(flow.end_date, format, CultureInfo.InvariantCulture);
            vlog.Vcompany = flow.visitor_comp_name;
            vlog.Vnum = Convert.ToInt64(flow.guest_Count);
            vlog.Status = ProcessStatus.WaitToEnter;
            if (vlog.VendTime <= DateTime.Now)
                vlog.Status = ProcessStatus.GoneOut;

            StringBuilder sp = new StringBuilder();
            if (!flow.visitor_reason.IsNullOrEmpty())
                sp.AppendLine($"來訪原因：{flow.visitor_reason}");
            if (!flow.visitor_addr.IsNullOrEmpty())
                sp.AppendLine($"參觀地點：{flow.visitor_addr}");
            if (!flow.visitor_dept.IsNullOrEmpty())
                sp.AppendLine($"參觀單位：{flow.visitor_dept}");
            if (!flow.req_services.IsNullOrEmpty())
                sp.AppendLine($"支援事項：{flow.req_services}");
            if (!flow.meeting_room.IsNullOrEmpty())
                sp.AppendLine($"會議安排：{flow.meeting_room}  {flow.meeting_start}至{flow.meeting_end}");

            vlog.Vreason = sp.ToString();
            if (vlog.Sex == SexType.Man)
                vlog.Vimg = "http://192.168.0.203:5005/upload/ComImg/customer_man.jpeg";
            else
                vlog.Vimg = "http://192.168.0.203:5005/upload/ComImg/customer_woman.jpeg";

            return vlog;
        }
        private Dictionary<string, int> DoorEventType()
        {
            Dictionary<string, int> dic = new Dictionary<string, int>();
            dic.Add("认证成功等待远程开门", 197390);
            dic.Add("卡不属于多重认证群组", 197391);
            dic.Add("常关时段开始", 198148);
            dic.Add("常关时段结束", 198150);
            dic.Add("开门超时", 198400);
            dic.Add("常开时段开始", 198401);
            dic.Add("常开时段结束", 198402);
            dic.Add("进入首卡常开状态", 198404);
            dic.Add("结束首卡常开状态", 198405);
            dic.Add("门被外力开启", 198657);
            dic.Add("正常开门", 198913);
            dic.Add("按钮开门", 198916);
            dic.Add("远程软件开门", 198919);
            dic.Add("远程软件常开", 198922);
            dic.Add("远程软件常闭", 199172);
            dic.Add("正常关门", 199169);
            dic.Add("远程软件关门", 199171);
            dic.Add("门锁打开", 199941);
            dic.Add("门锁关闭", 199942);
            dic.Add("读卡器防拆报警 ", 200453);
            dic.Add("读卡器防拆报警恢复", 200454);
            dic.Add("读卡器掉线报警 ", 200455);
            dic.Add("读卡器掉线报警恢复", 200456);
            dic.Add("设备防拆报警", 199708);
            dic.Add("设备防拆恢复", 199709);
            dic.Add("装置离线", 199710);
            dic.Add("装置连线", 199711);
            dic.Add("重新启动", 199712);
            dic.Add("系统初始化", 199713);
            dic.Add("数据被损坏", 199714);
            dic.Add("呼叫中心（1T500专有）", 199715);
            dic.Add("门禁(支持事件订阅 & 门禁点事件查询),刷卡 + 指纹认证通过", 196885);
            dic.Add("指纹 + 密码认证通过", 196887);
            dic.Add("合法卡比对通过", 198914);
            dic.Add("刷卡 + 密码认证通过", 198915);
            dic.Add("密码错误", 197121);
            dic.Add("输入卡号错误", 197122);
            dic.Add("输入密码而非卡号", 197123);
            dic.Add("卡号长度错误", 197124);
            dic.Add("卡号数字检查错误", 197125);
            dic.Add("无此卡号", 197634);
            dic.Add("卡号过期", 197633);
            dic.Add("刷卡 + 密码不开门", 198145);
            dic.Add("卡未分配权限", 197635);
            dic.Add("刷卡 + 指纹 + 密码通过", 196886);
            dic.Add("工号 + 密码认证通过", 196897);
            dic.Add("指纹比对通过", 197127);
            dic.Add("指纹比对失败", 197128);
            dic.Add("刷卡 + 指纹 + 密码失败", 197136);
            dic.Add("刷卡 + 指纹 + 密码超时", 197137);
            dic.Add("指纹不存在", 197140);
            dic.Add("工号 + 密码认证失败", 197158);
            dic.Add("人脸 + 指纹认证通过", 196888);
            dic.Add("人脸 + 指纹认证失败", 197141);
            dic.Add("人脸 + 指纹认证超时", 197142);
            dic.Add("人脸 + 密码认证通过", 196889);
            dic.Add("人脸 + 密码认证失败", 197143);
            dic.Add("人脸 + 密码认证超时", 197144);
            dic.Add("人脸 + 刷卡认证通过", 196890);
            dic.Add("人脸 + 刷卡认证失败", 197145);
            dic.Add("人脸 + 刷卡认证超时", 197146);
            dic.Add("人脸 + 密码 + 指纹认证通过", 196891);
            dic.Add("人脸 + 密码 + 指纹认证失败", 197147);
            dic.Add("人脸 + 密码 + 指纹认证超时", 197148);
            dic.Add("人脸 + 刷卡 + 指纹认证通过", 196892);
            dic.Add("人脸 + 刷卡 + 指纹认证失败", 197149);
            dic.Add("人脸 + 刷卡 + 指纹认证超时", 197150);
            dic.Add("人脸认证通过", 196893);
            dic.Add("人脸认证失败", 197151);
            dic.Add("智能分析失败", 197160);
            dic.Add("真人检测失败", 197161);
            dic.Add("人证比对通过", 197162);
            dic.Add("人证比对失败", 197163);
            dic.Add("首卡比对通过", 196874);
            dic.Add("行动不便人士卡比对通过", 196875);
            dic.Add("多重认证成功", 196883);
            dic.Add("多重认证超级密码成功", 196884);
            dic.Add("巡查卡比对通过", 198918);
            dic.Add("超级卡比对通过", 198921);
            dic.Add("胁迫卡比对通过", 199425);
            dic.Add("反潜回认证失败", 197383);
            dic.Add("卡不在多重认证时段内", 197392);
            dic.Add("多重认证超级密码错误", 197393);
            dic.Add("多重认证远程认证失败", 197394);
            dic.Add("行动不便人士卡未分配权限", 197395);
            dic.Add("胁迫卡未分配权限", 197396);
            dic.Add("超级卡未分配权限", 197397);
            dic.Add("多重认证重复认证", 197400);
            dic.Add("多重认证超时", 197401);
            dic.Add("互锁中无法开门", 198146);
            dic.Add("反潜回读卡器刷卡无效", 198149);
            dic.Add("巡查卡无效时段 ", 197399);
            dic.Add("互锁门未关闭", 198658);
            dic.Add("黑名单事件", 197889);
            dic.Add("时段组错误", 197384);
            dic.Add("假期权限不合", 197378);
            dic.Add("权限不合", 197377);
            dic.Add("指纹 + 密码认证失败", 197138);
            dic.Add("刷卡 + 指纹认证失败", 197134);
            dic.Add("卡号认证超次报警", 199429);
            dic.Add("解除警报", 199681);
            dic.Add("胁迫报警", 199428);
            return dic;
        }

        /// <summary>
        /// 获取用户最顶级的机构代码
        /// </summary>
        /// <param name="userOrgId"></param>
        /// <returns></returns>
        private string GetOrgTopCode(List<SysOrg> dbOrgs, long orgId)
        {
            string orgCode = string.Empty;
            var org = dbOrgs.FirstOrDefault(r => r.Id == orgId);
            if (org.Pid == 0)
            {
                return org.Code;
            }
            return GetOrgTopCode(dbOrgs, org.Pid);
        }
        private async Task<string> GetCurrentWeChatToken(string settingCode, SysUser user, ISqlSugarClient _db)
        {
            var dbOrgs = await _db.Queryable<SysOrg>().ToListAsync();

            //金茂厂企业微信Token配置
            string tokenSetting = string.Empty;
            var config = await CommonUtil.GetConfigValue(settingCode);
            foreach (var item in config.Split('|'))
            {
                var settings = item.Split(',');
                var dbOrgCode = GetOrgTopCode(dbOrgs, user.OrgId);
                if (settings[0].Equals(dbOrgCode))
                {
                    tokenSetting = settings[1];
                }
            }
            return tokenSetting;
        }
        #region 企业微信用户邀请与删除
        public async Task<WchatReulst> OperationWchatUser(SysUser user, ISqlSugarClient _db)
        {
            var tokenSetting = await GetCurrentWeChatToken("visitor_wchat_token_setting", user, _db);
            var config = await CommonUtil.GetConfigValue(tokenSetting);
            var wchatTokenRequestConfig = config.Split(',');

            List<dept_user> wchatUserList = new List<dept_user>();
            var wchatGetUserIdsResponseString = await WarnGetUserIds(wchatTokenRequestConfig);
            var result = wchatGetUserIdsResponseString.ToJsonEntity<WchatReulst>();
            if (result.success)
            {
                JObject obj = JObject.Parse(wchatGetUserIdsResponseString);
                wchatUserList = obj[nameof(dept_user)].ToString().ToJsonEntity<List<dept_user>>();
            }
            if (!wchatUserList.Any(r => r.userid == user.JobNum))
            {

                var apiRes = await WarnCreateUser(user.JobNum, user.RealName, user.Phone, wchatTokenRequestConfig[0], wchatTokenRequestConfig[1]);
                result = apiRes.ToJsonEntity<WchatReulst>();
            }
            return result;
        }

        /// <summary>
        /// 发送企业微信邀请信息给到用户
        /// </summary>
        /// <param name="userid"></param>
        /// <param name="name"></param>
        /// <param name="mobile"></param>
        /// <param name="corpid"></param>
        /// <param name="corpsecret"></param>
        /// <returns></returns>
        public async Task<string> WarnCreateUser(string userid, string name, string mobile, string corpid, string corpsecret)
        {
            string accessToken = _sysCacheService.Get<string>(CacheConst.KeyQyvxTokenAddUser);
            if (accessToken == null)
            {
                string url = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}";
                var tokenRes = await _resilienceHttpClient.GetStringAsync(url);
                var jsonObj = JsonConvert.DeserializeObject<JObject>(tokenRes);
                accessToken = jsonObj["access_token"].Value<string>();
                var expiresIn = jsonObj["expires_in"].Value<int>();
                _sysCacheService.Set(CacheConst.KeyQyvxTokenAddUser, accessToken, TimeSpan.FromTicks(expiresIn * TimeSpan.TicksPerSecond));
            }
            string url2 = "https://qyapi.weixin.qq.com/cgi-bin/user/create?access_token=" + accessToken;
            var item = new
            {
                userid = userid,
                name = name,
                mobile = mobile,
                department = new[] { 1 } //1就是将用户拉取到列表，不拉取进群
            };
            var apiRes = await _resilienceHttpClient.PostAsync(url2, item);
            return apiRes;
        }

        public async Task<string> WarnGetUser(string userid, string[] wchatTokenRequestConfig)
        {
            string accessToken = _sysCacheService.Get<string>(CacheConst.KeyQyvxTokenAddUser);
            if (accessToken == null)
            {
                string url = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={wchatTokenRequestConfig[0]}&corpsecret={wchatTokenRequestConfig[1]}";
                var tokenRes = await _resilienceHttpClient.GetStringAsync(url);
                var jsonObj = JsonConvert.DeserializeObject<JObject>(tokenRes);
                accessToken = jsonObj["access_token"].Value<string>();
                var expiresIn = jsonObj["expires_in"].Value<int>();
                _sysCacheService.Set(CacheConst.KeyQyvxTokenAddUser, accessToken, TimeSpan.FromTicks(expiresIn * TimeSpan.TicksPerSecond));
            }
            string url2 = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=" + accessToken;
            var item = new
            {
                userid = userid
            };
            var apiRes = await _resilienceHttpClient.PostAsync(url2, item);
            return apiRes;
        }

        public async Task<string> WarnGetUserIds(string[] wchatTokenRequestConfig)
        {
            string accessToken = _sysCacheService.Get<string>(CacheConst.KeyQyvxTokenAddUser);
            if (accessToken == null)
            {
                string url = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={wchatTokenRequestConfig[0]}&corpsecret={wchatTokenRequestConfig[1]}";
                var tokenRes = await _resilienceHttpClient.GetStringAsync(url);
                var jsonObj = JsonConvert.DeserializeObject<JObject>(tokenRes);
                accessToken = jsonObj["access_token"].Value<string>();
                var expiresIn = jsonObj["expires_in"].Value<int>();
                _sysCacheService.Set(CacheConst.KeyQyvxTokenAddUser, accessToken, TimeSpan.FromTicks(expiresIn * TimeSpan.TicksPerSecond));
            }
            string url2 = "https://qyapi.weixin.qq.com/cgi-bin/user/list_id?access_token=" + accessToken;
            var item = new { };
            var apiRes = await _resilienceHttpClient.PostAsync(url2, item);
            return apiRes;
        }
        #endregion

    }


    public class CarCrossCallBack
    {
        public string method { get; set; }

        public Params @params { get; set; }
    }

    public class Params
    {
        public Params()
        {
            events = new List<Event>();
        }
        /// <summary>
        /// 事件从接收者（程序处理后）发出的时间
        /// </summary>
        public string sendTime { get; set; }
        /// <summary>
        /// 事件类别
        /// </summary>
        public string ability { get; set; }
        public List<Event> events { get; set; }
    }

    public class Event
    {
        /// <summary>
        /// 事件唯一标识
        /// </summary>
        public string eventId { get; set; }
        /// <summary>
        /// 事件源编号，物理设备是资源编号
        /// </summary>
        public string srcIndex { get; set; }
        /// <summary>
        /// 事件源资源类型
        /// </summary>
        public string srcType { get; set; }
        /// <summary>
        /// 事件类型
        /// </summary>
        public int? eventType { get; set; }
        /// <summary>
        /// 事件状态  
        ///0-瞬时
        ///1-开始
        ///2-停止
        ///4-事件联动结果更新
        ///5-事件图片异步上传
        /// </summary>
        public int? status { get; set; }
        /// <summary>
        /// 脉冲超时时间   单位：秒
        /// </summary>
        public int? timeout { get; set; }
        /// <summary>
        /// 事件发生时间（设备时间）
        /// </summary>
        public string happenTime { get; set; }
        /// <summary>
        /// 事件发生的事件源父设备
        /// </summary>
        public string srcParentIdex { get; set; }
        /// <summary>
        /// 事件详情
        /// </summary>
        public HKSubData data { get; set; }
    }
    //https://open.hikvision.com/docs/docId?productId=5c67f1e2f05948198c909700&version=%2Ff95e951cefc54578b523d1738f65f0a1&tagPath=%E9%99%84%E5%BD%95-%E9%99%84%E5%BD%95D%20%E4%BA%8B%E4%BB%B6%E5%88%97%E8%A1%A8-%E9%99%84%E5%BD%95D3%20%E8%BD%A6%E8%BE%86%E7%AE%A1%E7%90%86%E4%BA%8B%E4%BB%B6-%E9%99%84%E5%BD%95D3.1%20%E5%81%9C%E8%BD%A6%E5%9C%BA%E4%BA%8B%E4%BB%B6
    public class HKSubData
    {
        public long? Id { get; set; }
        /// <summary>
        /// 是否黑名单标识（1-黑名单 0-非黑名单）
        /// </summary>
        public int? alarmCar { get; set; }
        /// <summary>
        /// 车辆属性名称
        /// </summary>
        public string carAttributeName { get; set; }
        /// <summary>
        /// 卡号
        /// </summary>
        public string cardNo { get; set; }
        /// <summary>
        /// 事件号
        /// 1:压线事件
        ///    2:上传图片
        ///    3:入场
        ///    4:出场
        ///    5:车牌矫正
        ///    6:图片重传
        /// </summary>
        public int? eventCmd { get; set; }
        /// <summary>
        /// 	事件编号
        /// </summary>
        public string eventIndex { get; set; }
        /// <summary>
        /// 出入口编号
        /// </summary>
        public string gateIndex { get; set; }
        /// <summary>
        /// 出入口名称
        /// </summary>
        public string gateName { get; set; }
        /// <summary>
        /// 进出场类型，0：进场，1：出场
        /// </summary>
        public int? inoutType { get; set; }
        /// <summary>
        /// 停车库编号
        /// </summary>
        public string parkIndex { get; set; }
        /// <summary>
        /// 停车库名称
        /// </summary>
        public string parkName { get; set; }
        /// <summary>
        /// 车牌号
        /// </summary>
        public string plateNo { get; set; }
        /// <summary>
        /// 车道编号
        /// </summary>
        public string roadwayIndex { get; set; }
        /// <summary>
        /// 车道名称
        /// </summary>
        public string roadwayName { get; set; }
        /// <summary>
        /// 车道类型 1：入场车道 2：出场不收费车道 3：出场缴费车道 4：中央缴费车道
        /// </summary>
        public int roadwayType { get; set; }
        /// <summary>
        /// 时间
        /// </summary>
        public string time { get; set; }

    }

    //public class Data
    //{
    //    /// <summary>
    //    /// 事件唯一标识
    //    /// </summary>
    //    public string eventIndex { get; set; }
    //    /// <summary>
    //    /// 车牌号
    //    /// </summary>
    //    public string plateNo { get; set; }
    //    /// <summary>
    //    /// 车牌类型key
    //    /// </summary>
    //    public string plateType { get; set; }
    //    /// <summary>
    //    /// 车牌类型名称
    //    /// </summary>
    //    public string plateTypeName { get; set; }
    //    /// <summary>
    //    /// 车辆类型key
    //    /// </summary>
    //    public string vehicleType { get; set; }
    //    /// <summary>
    //    /// 车辆类型名称
    //    /// </summary>
    //    public string vehicleTypeName { get; set; }
    //    /// <summary>
    //    /// 过车时间
    //    /// </summary>
    //    public string crossTime { get; set; }
    //    /// <summary>
    //    /// 整型，速度值
    //    /// </summary>
    //    public int? speed { get; set; }
    //    /// <summary>
    //    /// 卡口点主键
    //    /// </summary>
    //    public string monitorId { get; set; }
    //    /// <summary>
    //    /// 卡口点名称
    //    /// </summary>
    //    public string monitorName { get; set; }
    //    /// <summary>
    //    /// 卡口点编号
    //    /// </summary>
    //    public string monitorIndexCode { get; set; }
    //    /// <summary>
    //    /// 违法类型
    //    /// </summary>
    //    public string illegalType { get; set; }
    //}
}
